package com.carey.blog.repository.impl;

import java.util.Map;
import java.util.logging.Logger;

import org.json.JSONException;
import org.json.JSONObject;

import com.carey.blog.framework.latke.Keys;
import com.carey.blog.framework.latke.repository.RepositoryException;
import com.carey.blog.framework.latke.repository.gae.AbstractGAERepository;
import com.carey.blog.model.Article;
import com.carey.blog.model.BlogSync;
import com.carey.blog.repository.ExternalArticleSoloArticleRepository;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

/**
 * External blog article Google App Engine repository.
 * 
 */
public final class ExternalArticleSoloArticleGAERepository extends
		AbstractGAERepository implements ExternalArticleSoloArticleRepository {

	/**
	 * Logger.
	 */
	private static final Logger LOGGER = Logger
			.getLogger(ExternalArticleSoloArticleGAERepository.class.getName());

	@Override
	public String getName() {
		return BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE + "_" + Article.ARTICLE;
	}

	@Override
	public String getSoloArticleId(final String externalArticleId,
			final String externalBloggingSys) throws RepositoryException {
		final Query query = new Query(getName());
		query.addFilter(BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_ID,
				Query.FilterOperator.EQUAL, externalArticleId);
		query.addFilter(BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS,
				Query.FilterOperator.EQUAL, externalBloggingSys);
		final PreparedQuery preparedQuery = getDatastoreService()
				.prepare(query);
		final Entity entity = preparedQuery.asSingleEntity();

		if (null == entity) {
			return null;
		}

		final Map<String, Object> properties = entity.getProperties();

		return (String) properties.get(Article.ARTICLE + "_" + Keys.OBJECT_ID);
	}

	@Override
	public JSONObject getSoloArticle(final String externalArticleId,
			final String externalBloggingSys) throws RepositoryException {
		final JSONObject relation = getByExternalArticleId(externalArticleId,
				externalBloggingSys);
		if (null == relation) {
			return null;
		}

		try {
			final JSONObject ret = relation;
			final String articleId = relation.getString(Article.ARTICLE + "_"
					+ Keys.OBJECT_ID);
			// replace oId for article
			ret.put(Keys.OBJECT_ID, articleId);
			// remove relation properties
			ret.remove(Article.ARTICLE + "_" + Keys.OBJECT_ID);
			ret.remove(BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS);
			ret.remove(BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_ID);

			return ret;
		} catch (final JSONException e) {
			throw new RepositoryException(e);
		}
	}

	@Override
	public JSONObject getByExternalArticleId(final String externalArticleId,
			final String externalBloggingSys) throws RepositoryException {
		final Query query = new Query(getName());
		query.addFilter(BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_ID,
				Query.FilterOperator.EQUAL, externalArticleId);
		query.addFilter(BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS,
				Query.FilterOperator.EQUAL, externalBloggingSys);
		final PreparedQuery preparedQuery = getDatastoreService()
				.prepare(query);
		final Entity entity = preparedQuery.asSingleEntity();

		if (null == entity) {
			return null;
		}

		return entity2JSONObject(entity);
	}

	@Override
	public JSONObject getBySoloArticleId(final String soloArticleId,
			final String externalBloggingSys) throws RepositoryException {
		final Query query = new Query(getName());
		query.addFilter(Article.ARTICLE + "_" + Keys.OBJECT_ID,
				Query.FilterOperator.EQUAL, soloArticleId);
		query.addFilter(BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS,
				Query.FilterOperator.EQUAL, externalBloggingSys);
		final PreparedQuery preparedQuery = getDatastoreService()
				.prepare(query);
		final Entity entity = preparedQuery.asSingleEntity();

		if (null == entity) {
			return null;
		}

		return entity2JSONObject(entity);
	}

	/**
	 * Gets the {@link ExternalArticleSoloArticleGAERepository} singleton.
	 * 
	 * @return the singleton
	 */
	public static ExternalArticleSoloArticleGAERepository getInstance() {
		return SingletonHolder.SINGLETON;
	}

	/**
	 * Private default constructor.
	 */
	private ExternalArticleSoloArticleGAERepository() {
	}

	/**
	 * Singleton holder.
	 * 
	 */
	private static final class SingletonHolder {

		/**
		 * Singleton.
		 */
		private static final ExternalArticleSoloArticleGAERepository SINGLETON = new ExternalArticleSoloArticleGAERepository();

		/**
		 * Private default constructor.
		 */
		private SingletonHolder() {
		}
	}
}
